home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / ccmd / ccmd.guide < prev    next >
Encoding:
Text File  |  1990-12-18  |  34.3 KB  |  896 lines

  1.  
  2.  
  3.                  CCMD
  4.  
  5.           TOPS-20 COMND JSYS EMULATION PACKAGE IN C
  6.  
  7.               Programmer's Guide
  8.  
  9.  
  10.  
  11. INTRODUCTION:
  12.  
  13. CCMD is a general parsing mechanism for developing User Interfaces to
  14. programs.  It is based on the functionality of TOPS-20's COMND Jsys.
  15. CCMD allows a program to parse for various field types (file names,
  16. user names, dates and times, keywords, numbers, arbitrary text,
  17. tokens, etc.).  It is meant to supply a homogeneous user interface
  18. across a variety of machines and operating systems for C programs.
  19. The library defines various default actions (user settable), and
  20. allows field completion, help, file indirection, comments, etc on a
  21. per field basis.  Future plans include command line editing and ports
  22. to other operating systems (such as VMS).  See the CCMD man page for
  23. more details on the user's view of CCMD.  If you are installing CCMD,
  24. see the INSTALL file.
  25.  
  26.  
  27. 1) MACHINES/OPERATING SYSTEMS:
  28.  
  29. CCMD currently runs under UNIX 4.2/4.3 BSD, Ultrix 1.2/2.0, System V,
  30. SunOS, Pyramid, DYNIX (Sequent-Balance 21000), Celerity, and MS-DOS
  31. 3.1.
  32.  
  33.  
  34. 2) INCLUDE FILES:
  35.  
  36. The file "ccmd.h" should be included in your C source if you wish to
  37. use the ccmd package.  Sometimes this will be found in the "local"
  38. subdirectory of the include directory.  This file contains definitions
  39. for functions, flags, error codes, and structure declarations.
  40.  
  41. This file will include some other CCMD files: "cmfnc.h", "ccmdmd.h",
  42. "datime.h", and "cmkeyval.h".
  43.  
  44. Function specific symbols and declarations are in "cmfnc.h".  Machine
  45. dependent macros and declarations are in "ccmdmd.h".  Day and time
  46. parse related declarations are in "datime.h".  "cmkeyval.h" declares
  47. the types "keyval" and pointer to function (cmprocptr).
  48.  
  49.  
  50. 3) DATA STRUCTURES:
  51.  
  52. Below are a few of the data structures that you need to know about in
  53. order to use ccmd.
  54.  
  55. a) fdb
  56.  
  57. The fdb structures hold information required to parse specific fields
  58. of a command line.
  59.  
  60. typedef struct FDB {
  61.     int    _cmfnc;        /* Function code for this field */
  62.     int    _cmffl;        /* Function specific parse flags */
  63.     struct FDB * _cmlst;    /* Link to alternate FDB */
  64.     pdat    _cmdat;        /* Function specific parsing data */
  65.     char *    _cmhlp;        /* pointer to help string */
  66.     char *    _cmdef;        /* pointer to default string */
  67.     brktab * _cmbrk;    /* pointer to special break table */
  68. } fdb;
  69.  
  70. i) _cmfnc:
  71.  
  72. The function code specifies what type of parse is to be done.  
  73. The function code (_cmfnc) can be one of the following:
  74.  
  75.     _CMCFM        parse for a confirm (carriage return)
  76.     _CMKEY        parse for a keyword (from a table of keywords)
  77.     _CMNUM        parse a number (of the specified radix)
  78.     _CMQST        parse a quoted string
  79.     _CMNOI        parse a noise (guide) string
  80.     _CMTXT        parse text up to end of line
  81.     _CMFLD        parse a single field 
  82.     _CMSWI        parse a switch (switch character followed by keyword)
  83.     _CMTOK        parse a token
  84.     _CMTAD        parse a time and/or date specification
  85.     _CMFIL        parse a file name
  86.     _CMUSR        parse a user name
  87.     _CMGRP        parse a group name
  88.     _CMPARA        parse a "paragraph" of text
  89.     _CMCHAR        parse a single character
  90.  
  91. Each of these parse types will be discussed in detail later.
  92.  
  93. ii) _cmffl:
  94.  
  95. _cmffl is the function specific parse flags for the above types of
  96. parses.  (See the discussion on the individual parse types for more
  97. detail on this.)
  98.  
  99. In addition to the function specific flags, there is one flag that is
  100. common to all parse types.  This is CM_SDH which is used to suppress
  101. the default help message associated with the parse type.  This is
  102. commonly used when you wish to supply your own help message (see
  103. _cmhlp below).
  104.  
  105. iii) _cmlst:
  106.  
  107. _cmlst is a pointer to an alternate fdb.  A chain of fdbs may be
  108. passed to the parser which will try to use one of the fdb's in a
  109. successful parse.  The fdbs in the chain are considered in the order
  110. that they are linked in, and thus it is up to the programmer to chain
  111. them in the proper order in cases when an input may satisfy more than
  112. one fdb.
  113.  
  114. The last fdb's _cmlst field should be the NULL pointer.
  115.  
  116. The function fdbchn() may be used to set up the chain.  Further
  117. details appear later in this guide.
  118.  
  119. iv) _cmhlp:
  120.  
  121. A help string may be provided in addition to or in place of the
  122. default help provided for a parse type.  Note that in parses with
  123. chained fdbs, the help messages appear in the order that the fdbs are
  124. chained.
  125.  
  126. To suppress the default help message associated with a parse type, the
  127. CM_SDH flag may be set in the fdb (see _cmffl above).
  128.  
  129. v) _cmdat:
  130.  
  131. The _cmdat field is used to supply parse type specific data to the
  132. parser.  See the discussion on the various parse types for more
  133. details on this field.
  134.  
  135. vi) _cmdef:
  136.  
  137. The _cmdef field is used to supply a default string to the parser.
  138. If no other fdb in the chain has parsed the command line successfully
  139. up to the current fdb, and if this fdb has a default string, then the
  140. parse will succeed as if the default had been typed by the user.
  141. Note, that the user can type some other string satisfying this fdb, in
  142. which case the user's data takes precedence.
  143.  
  144. vii) _cmbrk:
  145.  
  146. This field contains a pointer to a special break table to be used
  147. during this parse.  A break table specifies which characters are valid
  148. for this particular field.  All other characters will cause the parser
  149. to break out of this parse.  The structure of the break table (brktab)
  150. is discussed below.
  151.  
  152.  
  153. b) brktab
  154.  
  155. A break table specifies the characters that will cause the parser to
  156. break out of the current parse.
  157.  
  158. typedef struct BRKTAB {
  159.     char _br1st[16];    /* Bit array for initial character breaks */
  160.     char _brrest[16];    /* Bit array for subsequent breaks */
  161. } brktab;
  162.  
  163. brktab is a pair of 128-bit arrays specifying the break
  164. characteristics of the ASCII characters.  The _br1st array specifies
  165. characters which will break field input when they are typed as the
  166. first character of a field.  The _brrest array specifies characters
  167. that break in other than the first position.  Each array contains one
  168. bit per ASCII code, ordered according to the ASCII sequence.  The
  169. leftmost (most significant) bit of the first byte corresponds to ASCII
  170. code 0, and the rightmost bit of that same byte corresponds to ASCII
  171. code 7.  Leftmost bit of the second bit is for ASCII code 8, and so
  172. on.  When a bit is on, the corresponding character will act as a break
  173. character, otherwise it will not.
  174.  
  175. The default break tables for each parse type will be mentioned in the
  176. section describing the parse types.
  177.  
  178. XXX Mention break table utils in ccmdut when they get written XXX
  179. XXX Mention brk, document it, etc. XXX
  180. XXX Also, give an example where br1st and brrest are diff't. XXX
  181.  
  182. c) pval:
  183.  
  184. Pval is a union in which ccmd returns parsed values.  Each parse type
  185. will use one of the fields, whichever is appropriate.  The structure
  186. of pval is as follows:
  187.  
  188. typedef union PVAL {
  189.     int _pvint;            /* integer return value */
  190.     float _pvflt;            /* XXX floating point return value */
  191.     char _pvchr;            /* single character */
  192.     char *_pvstr;            /* string */
  193.     char **_pvstrvec;        /* XXX ??? XXX */
  194.         keyval _pvkey;            /* keyword and switch index */
  195.         datime _pvtad;            /* date and/or time */
  196.         pvfil _pvfil;            /* file(s) */
  197.         struct passwd ** _pvusr;    /* passwd entries for parsed users */
  198.         struct group ** _pvgrp;        /* group entries for parsed groups */
  199.         char * _pvpara;            /* "paragraph" of text */
  200. } pval;
  201.  
  202. Here is a list of all the parse types and the field to look at for the
  203. parsed value:
  204.  
  205.     Parse type         Field      Comment
  206.     ------------------------------------------------------------
  207.     Confirm     (CMCFM)     <none>      parse succeeds/fails
  208.     Keyword        (CMKEY)     _pvkey      value specified for keyword
  209.     Number (integer)(CMNUM)     _pvint    
  210.     Quoted string    (CMQST)  _pvstr      quotes are stripped off XXX ?
  211.     Noise string    (CMNOI)     <none>      parse succeeds/fails
  212.     Text string    (CMTXT)     _pvstr
  213.     Field        (CMFLD)  _pvstr
  214.     Switch        (CMSWI)  _pvkey      value specified for switch
  215.     Token        (CMTOK)  <none>      parse succeeds/fails
  216.     Date/time    (CMTAD)  _pvtad      struct datime (see below)
  217.     File name(s)    (CMFIL)  _pvfil      array of char strings
  218.     User name(s)    (CMUSR)  _pvusr      array of struct passwd
  219.     Group name(s)    (CMGRP)  _pvgrp      array of struct group
  220.     Paragraph    (CMPARA) _pvpara  char string
  221.     Character    (CMCHAR) _pvchr
  222.  
  223.  
  224. d) csb 
  225.  
  226. The csb structure holds information on the state of parsing a command
  227. line, as well as pointers to required buffers.  CCMD uses the global
  228. csb called cmcsb (externed in ccmd.h).
  229.  
  230. typedef struct CSB {
  231.     int     _cmflg;        /* flags describing parse state */
  232.     int    _cmflg2;    /* more flags */
  233.     FILE *  _cmij;        /* file for command input */
  234.     FILE *    _cmoj;        /* file for command output */
  235.     FILE *  _cmej;        /* file for error output */
  236.     char *    _cmrty;        /* pointer to prompt string */
  237.     int *    _cmbfp;        /* pointer to beginning of user input */
  238.     int *    _cmptr;        /* pointer to beg of next field to parse */
  239.     int     _cmcnt;        /* # of chars in buffer past _cmptr */
  240.     int    _cminc;        /* number of unparsed chars after _cmptr */
  241.     int *    _cmhst;        /* history parse point */
  242.     char *    _cmabp;        /* pointer to beginning of atom buffer */
  243.     int    _cmabc;        /* size of atom buffer */
  244.     char *    _cmwbp;        /* pointer to beginning of work buffer */
  245.     int    _cmwbc;        /* size of work buffer */
  246.     int (** _cmact)();    /* table of character action routines */
  247.     int     _cmbkc;            /* break character that caused deferred */
  248.                 /*  action or confirmation */
  249.     int    _cmcmx;        /* maximum column position on terminal */
  250.     int    _cmcol;        /* current column position on terminal */
  251.     int    _cmerr;        /* most recent parse error */
  252.     fdb *    _cmifd;        /* ptr to FDB giving an incomplete parse */
  253.     int     (* _cmrph)();    /* function to call when reparse is needed */
  254.     int     (* _cmerh)();    /* function to call on parse error */
  255.     char *  _cmntb;        /* comment to eol string */
  256.     char *    _cmnts;        /* delimited comment beginning */
  257.     char *    _cmnte;        /* delimited comment end */
  258.     int     _cmmax;        /* maximum number of help tokens to display */
  259.     int     (* _cmblh)();    /* function to call nonblocking and no data */
  260.     int     _cmwrp;        /* column to wrap at */
  261.     cmhist *_cmhist;    /* command history  structure */
  262. } csb;
  263.  
  264. Most of these fields are only used internally by CCMD.  The ones that
  265. are most likely to be used externally are _cmij, _cmoj, and _cmej --
  266. the input, output and error file descriptors.  Changing these
  267. redirects input and output for parsing.  Using them allows consistency
  268. when CCMD is using alternate input/output.  _cmerr is another field of
  269. interest, since it tells why CCMD failed in the most recent parse.
  270. _cmwrp is used for paragraph parses to do automatic word wrap, and is
  271. optimally settable by the user.  _cmact can be used to change the
  272. actions on various characters.  XXX how?  Why?
  273.  
  274. XXX general history description, mention history length setting
  275.  
  276. When debugging, there are a few other things you may want to look at
  277. to see what has been typed and what has been parsed.
  278. XXX describe what's in cmabp and cmwbp strings, maybe cmbfp
  279. Note, however, that these strings are not null-terminated -- you will
  280. want to check the length (_cmabc and _cmwbc, respectively) of the
  281. strings. 
  282.  
  283. At initialization time, you can set necessary fields in the csb using
  284. cmini(), as described below.
  285.  
  286.  
  287. e) datime
  288.  
  289. datime is the structure returned by a day and/or time parse (CMTAD).
  290. Below is what this structure looks like:
  291.  
  292. typedef struct DATIME {
  293.     short    _dtmon;        /* 0 = January, 11 = December */
  294.     short    _dtday;        /* 0 = first day of month */
  295.     int    _dtyr;
  296.     short    _dtdow;        /* day of week: 0 = Sunday, 6 = Saturday */
  297.     short    _dthr;        /* 0 to 23 */
  298.     short    _dtmin;
  299.     short    _dtsec;
  300.     int    _dttz;        /* time zone, # of mins west of Greenwich */
  301.                 /*  (this is the number of minutes to add */
  302.                 /*  in order to get GMT) */
  303.     int    _dttzc;        /* time zone code, one of TZ_XXX codes */
  304.                 /*  defined below, or -1 */
  305.     int    _dtdst;        /* additional minutes to shift due to */
  306.                 /*  daylight savings time (generally -60 */
  307.                 /*  when dst is in effect and 0 otherwise) */
  308. } datime;
  309.  
  310. 00:00:00 is considered the beginning of a day.  If only a date is parsed,
  311. the time returned will be 00:00:01 of the parsed date.
  312.  
  313. Note that most of these fields correspond to fields of the UNIX tm
  314. structure.  However, the datime structure's _dtday field starts at 0
  315. while the tm structure's tm_mday starts at 1.
  316.  
  317. XXX describe TZ_XXX's
  318.  
  319. f) keywrd
  320.  
  321. The keywrd structure is used for _CMKEY and _CMSWI parses.  It
  322. contains a keyword to be parsed and a value to identify which keyword
  323. was parsed.  It also contains a flag field for various flags.  After a
  324. successful parse, the parse value (_pvkey field) will be set to the
  325. keyword value of the matched keyword.
  326.  
  327. typedef struct KEYWRD {
  328.     char *    _kwkwd;        /* keyword string */
  329.     short    _kwflg;        /* flags (see below) */
  330.     keyval    _kwval;        /* arbitrary value, not used internally */
  331.                 /*  except for abbreviations... see KEY_ABR */
  332.                 /*  flag below */
  333. } keywrd;
  334.  
  335. A set of keywrds is stored in an array, usually (though not
  336. necessarily) in alphabetical order.  When a question mark is typed,
  337. they will be displayed in this order.
  338.  
  339. The flags that a keyword can have are: KEY_NOR, KEY_IGN, KEY_INV, and
  340. KEY_ABR.
  341.  
  342. KEY_NOR and KEY_IGN are two names for the same flag, which means
  343. ignore this keyword.  (KEY_NOR is for TOPS20 compatibility (CM%NOR),
  344. and KEY_IGN is an easier name to remember.)  This flag can be used to
  345. "turn off" certain keywords in a dynamic table without having to
  346. remove the entry.  (Sort of like the grey-shaded options in a
  347. MacIntosh menu.)  It can also be used to disallow certain
  348. abbreviations of other keywords -- so if you did not want the keyword
  349. "really-dangerous" to be shortened to "r" even if it was the only
  350. keyword starting with "r", you would add the keyword "r" with KEY_IGN
  351. turned on.  Note that this flag does NOT imply KEY_INV (see below),
  352. but you will probably always want to have ignored keywords be
  353. invisible.
  354.  
  355. KEY_INV makes a keyword invisible.  That is, the keyword will not show
  356. up when a question mark is typed.  This is most often used for
  357. synonyms, to avoid clutter.  Thus, if you have an "exit" command, but
  358. many of your users are accustomed to typing "q" to exit, you could
  359. have "quit" as an invisible keyword, probably with the same keyval as
  360. "exit". 
  361.  
  362. KEY_ABR makes this keyword be an abbreviation of another one.  Since a
  363. unique prefix of a keyword will match that keyword, this is used to
  364. make a non-unique prefix match a specific keyword.  To specify which
  365. keyword the abbreviation is for, the offset of the that keyword in the
  366. current table (starting with zero) is placed in the _kwval field.
  367. (The value returned when the abbreviation is typed is the value for
  368. that keyword.)
  369.  
  370. For example, if you have the keywords "delete" and
  371. "do-something-really-obscure-and-complicated", you could make "d" be
  372. an abbreviation for "delete".  Then a user typing just "d" would get
  373. the "delete" keyword, and ESC would finish the word "delete".  For
  374. this reason, the abbreviation should be a prefix of the other keyword,
  375. since otherwise CCMD cannot complete it.
  376.  
  377. The kwval field can be used in various ways.  During command parsing,
  378. you will probably want the key value to specify which function should
  379. be called for further parsing of the command.  This can be done in
  380. various ways.  One of the slickest ways is to make the actual address
  381. of the function be the value.  However, this does not work on all
  382. computer systems.  A similar method, which works anywhere but is a
  383. little harder to maintain, is to have an array of functions indexed by
  384. the key value.  Then you would call the function like this:
  385.  
  386.     (void) (*func_array[parseval._pvkey]) ();
  387.  
  388. g) keytab
  389.  
  390. The keytab structure holds information about the keywrd array for a
  391. keyword parse.
  392.  
  393. typedef struct KEYTAB {
  394.     int    _ktcnt;        /* number of keywords in table */
  395.     keywrd * _ktwds;    /* array of keyword entries */
  396. } keytab;
  397.  
  398. It can be set up as follows:
  399.  
  400. keytab footab = { (sizeof(foowrds)/sizeof(keywrd)), foowrds };
  401.  
  402. if foowrds is the name of a static keywrd array.
  403.  
  404. h) filblk
  405.  
  406. Used for file parses
  407. XXX
  408.  
  409. typedef struct FILBLK {
  410.     char **pathv;        /* NULL terminated vector of dirs */
  411.     char *exceptionspec;    /* regexp of exceptions */
  412.     char **def_extension;   /* list of extensions to use */
  413. } filblk;
  414.  
  415. The pathv field is used to give a path for filenames.  By default, the
  416. path is just ".", the current directory.  It should be a
  417. null-terrminated array of directory names (with no terminating slash).
  418. The exceptionspec is a regular expression describing filenames to
  419. ignore -- for example, "*.o" as an exception would make sense for an
  420. editor, which would probably only want text files.  def_extension is a
  421. null-terminated array of extensions, for completion.  This is useful
  422. if you want to parse for files that end with ".c", ".txt", or
  423. whatever. 
  424.  
  425. XXX what are exceptionspec and def_extension?
  426.  
  427. XXX para_data, para_actions
  428. XXX More data structures?
  429.  
  430. 4) PARSE TYPES:
  431.  
  432. Each of the function types that can be in the _cmfnc field of an fdb
  433. corresponds to a different type of thing CCMD can parse.
  434.  
  435. Keywords and switches, filenames, user names, and group names are all
  436. parsed rather similarly, since they can all be thought of as
  437. variations on a keyword parse.  That is, a question mark will actually
  438. list all the keywords, filenames, user or group names that match the
  439. current input (unless there are too many, defined by the _cmmax field
  440. of the csb).
  441.  
  442. a) _CMCFM
  443.  
  444. This is used to parse a confirm, or carriage return.  You can use the
  445. CCMD function confirm() to just parse a confirm, or chain a confirm in
  446. with other fdbs, making those other parse elements optional.
  447.  
  448. A confirm should be done at the end of most commands.  One exception
  449. is a command that ends with a text parse, since the confirm gets
  450. parsed as the terminator of the text.
  451.  
  452. _CMCFM takes neither function specific flags or data.
  453.  
  454. b) _CMKEY and _CMSWI
  455.  
  456. These two functions, keyword and switch, will try to match a keyword
  457. to one of a list of keywords (see keywrd and keytab data structures
  458. above).  A switch begins with a "switch character" (this is settable),
  459. usually a slash (/), and is more often optional.  These are like UNIX
  460. options and VMS or TOPS20 switches.
  461.  
  462. Keywords are often used at the beginning of a command parse, to pick
  463. out which of a list of commands will be executed.
  464.  
  465. The fdb for a keyword or switch parse needs a keytab (described above)
  466. in the _cmdat field.  Note that for a switch's keywrds, the switch
  467. character should not be in the keywrd strings.  This makes it possible
  468. to use the same keytab for both keywords and switches.
  469.  
  470. There are no function-specific flags in _cmffl for _CMKEY and _CMSWI.
  471.  
  472. c) _CMNUM
  473.  
  474. This is used to parse a number in any radix (up to 16 -- hexadecimal).
  475. The radix is specified as the _cmdat field of the fdb.  There are
  476. three flags possible for a number parse.  NUM_US parses for (XXX and
  477. returns?) an unsigned integer.  XXX NUM_BNP (break on
  478. non-punctuation)??  NUM_PO (parse-only) tells CCMD to parse something
  479. that qualifies as a number in the specified radix without determining
  480. what number it is.  In this case, you might want to look at the _cmabp
  481. field of the csb to find out what string was parsed.
  482.  
  483. d) _CMQST
  484.  
  485. This is used for parsing a quoted string.  It expects to see a double
  486. quote as the first character of the field, and will include everything
  487. up to the next double quote in the string.  A quoted string parse
  488. would be used when looking for a field that might contain spaces.  It
  489. is similar to a text parse (see _CMTXT below) but ends before the end
  490. of line.
  491.  
  492. XXX settable delimiters
  493.  
  494. e) _CMNOI
  495.  
  496. Noise words are a type of mid-parse comments used to give hints about
  497. what should be typed next, or what this command does.  Since noise
  498. words are not required to be typed, you will almost never want to
  499. build a _CMNOI fdb, but will most likely just use the noise() routine
  500. (see below).
  501.  
  502. Noise words are displayed on escape after the previous field has been
  503. successfully completed.  They are shown in parentheses to emphasize
  504. that they need not be typed.
  505.  
  506. The _cmdat field of a _CMNOI fdb should be the noise string (without
  507. parentheses).
  508.  
  509. f) _CMTXT
  510.  
  511. A text parse is used to parse about a line of any sort of text.  It is
  512. terminated at end of line.  For longer parses, see _CMPAR below.
  513.  
  514. g) _CMFLD
  515.  
  516. A field parse gets one "word" of the input string.  The word is
  517. delimited by whichever characters are in the current break mask.
  518.  
  519. There is one flag available for a field parse, FLD_EMPTY, which when
  520. set does not allow an empty field (otherwise, a cmfld parse can
  521. succeed without parsing any characters).
  522.  
  523. h) _CMTOK
  524.  
  525. A token can be either a one character punctuation or a sort of
  526. one-word keyword table.  A token must exactly match the input.
  527.  
  528. The token string is specified in the _cmdat field of the fdb.
  529.  
  530. The flag TOK_WAK means white space after the token is not required --
  531. this allows help on "?" to work immediately after the entire token is
  532. entered.
  533.  
  534. i) _CMTAD
  535.  
  536. One of the most complicated parses CCMD can do is a time and day
  537. parse.  It allows for a large number of different formats.  This is in
  538. part seen by the numerous flags available.
  539.  
  540. DTP_NTI: do not parse time
  541. DTP_N24: no 24-hour time format allowed
  542. DTP_NTM: no AM/PM specifier allowed
  543. DTP_NIS: seconds may not be specified
  544. DTP_AIS: seconds must be specified after colon
  545. DTP_NAC: colon cannot appear between hours and minutes
  546. DTP_AAC: colon must appear between hours and minutes
  547. DTP_AHM: first number in time cannot be both hours and minutes
  548. DTP_AMS: first number in time is both hours and minutes unless too
  549.       many colons for this
  550. DTP_NTZ: no time zone allowed in input
  551. DTP_NDA: do not parse date
  552. DTP_NNM: month may not be numeric
  553. DTP_SNM: second of two date numbers is month (unless second number is
  554.       greater than 12)
  555. DTP_ERR: do not swap month/day numbers if DTP_SNM setting implies range error
  556. DTP_NDW: do not allow day-of-week in input
  557. DTP_NSP: do not allow time to split date before year, as BSD's ctime
  558.       call does (e.g. Saturday, 9 March 9:52am 1986)
  559.  
  560. As an example, here are some of the formats accepted for Monday,
  561. July 25, 1988 at 6:30 pm.
  562.  
  563.     7-25-88 18:30
  564.     25-7-1988 18:30
  565.     July 25, 1988 6:30 PM
  566.     Mon July 25 18:30:00 EDT 1988
  567.     Monday, July 25, 1988 630 p
  568.  
  569. j) _CMFIL
  570.  
  571. Another of CCMD's more complicated parses is the filename parse.  In
  572. addition to the options available via an optional filblk structure
  573. (described above) in the _cmdat field, there are many flags.
  574.  
  575. Since wildcards (and, eventually, regular expressions) can be allowed
  576. in the filename, it is possible to parse more than one file name, so
  577. all matching filenames are returned in an array of strings, terminated
  578. by a NULL string pointer.
  579.  
  580. FIL_OLD: existing file
  581. FIL_PO: file need not exist (parse-only)
  582. FIL_SDH: don't give standard help (list of filenames)
  583. FIL_DIR: a directory
  584. FIL_RD: a readable file
  585. FIL_WR: a writable file
  586. FIL_EXEC: an executable file
  587. FIL_HID: a hidden file (in MSDOS)
  588. FIL_SYS: a system file (in MSDOS)
  589. FIL_WLD: wild cards allowed
  590. FIL_REGEXP: regular expressions allowed (not yet implemented)
  591. FIL_NOPTH: only display filename in help, not whole directory path
  592. FIL_NOEXT: don't display extension in help
  593. FIL_TYPE: display the type of file in help
  594. FIL_NODIR: don't complete on directories (for parsing non-directory files)
  595. FIL_RW: a readable and writable file
  596.  
  597. The union of the files matching the flags is used -- thus using the
  598. flags FIL_RD and FIL_WR will parse for a file which is either readable
  599. or writable or both.
  600.  
  601. Setting no flags at all will parse for any (existing) file.
  602.  
  603. k) _CMUSR and _CMGRP
  604.  
  605. These can be used to parse for a user or group name on the local
  606. machine.  The user must exist and be in the password file.  The group
  607. must be in the group file.  The name may contain wildcards (if
  608. USR_WILD or GRP_WILD is set), so an array containing password (or
  609. group) entries for all matching names is returned.  Again, the end of
  610. the array is the first NULL entry.
  611.  
  612. USR_WILD or GRP_WILD: allow wildcards in user/group names
  613. USR_NOUPD or GRP_NOUPD: defer update of user or group table, even if
  614.       /etc/passwd or /etc/groups has been updated -- this is used
  615.       when there are so many users/groups on the system that an
  616.       update will cause a significant wait
  617. USR_UPDONLY or GRP_UPDONLY: forced update of user or group table
  618.       (parse will fail) -- allows table to be updated with no
  619.       parse done.  When using this flag, you must trap errors
  620.       yourself (using cmseter() as described below), or a "no such
  621.       user/group" error will be displayed
  622.  
  623. l) _CMPARA
  624.  
  625. For extended amounts of text, you will want to use the paragraph
  626. parse.  (A "paragraph" can really be more than one paragraph, but we
  627. will continue to use that phrase.)  _CMPARA cannot be chained with
  628. other fdbs (since it wouldn't make sense anyway).  It will continue
  629. parsing until an end-of-text (usually control-D) is typed.  In
  630. addition, several utility functions can be invoked while the paragraph
  631. is being typed.
  632.  
  633. Control-B is used to insert a file into the paragraph.  It will prompt
  634. for a file name and insert the contents of the file.
  635.  
  636. Control-E invokes the user's editor (either from their EDITOR
  637. environment variable or a default) on the current paragraph, by
  638. writing it out to a temporary file.  Once the editor exits, CCMD reads
  639. the paragraph back in from the file.
  640.  
  641. Control-F runs the paragraph through a filter.  This is similar to the
  642. edit command, but is used with non-interactive programs.  For example,
  643. if you had a program that took text and put it into two columns, you
  644. could use this as a filter after finishing your paragraph.
  645.  
  646. Control-K can be used to redisplay the paragraph.  This is useful for
  647. when some other program writes to the user's screen.  Similarly,
  648. control-L redisplays the paragraph after first clearing the screen.
  649.  
  650. Control-N is used to abort the parse, and is similar to the effect of
  651. control-U on a line.
  652.  
  653. Control-P executes a command and inserts the output into the
  654. paragraph.  This can be simulated in Unix by sending the output of a
  655. command to a file and then using ^B to insert the file.
  656.  
  657. Space, tab, and newline invoke a special word wrapping routine.  The
  658. column at which wrapping is done is specified in the _cmwrp field of
  659. the csb (see above).  If the number is positive, it is taken as an
  660. absolute value.  If negative, it is subtracted from the number of
  661. columns on the user's screen.  A zero value turns wrapping off.
  662.  
  663. You can add your own set of routines to be used during paragraph
  664. parsing using the para_actions structure described above.  Also, you
  665. can continue a paragraph parse (or start one with some text already
  666. entered) by filling in the buf field of the para_data structure.  If
  667. you do this kind of modification, the para_data structure goes in the
  668. _cmdat field of the fdb.
  669.  
  670. The one flag available for _CMPARA is PARA_DEF, which controls the
  671. effect of the para_actions structure (within the para_dat in the
  672. _cmdat field).  If PARA_DEF is set, the default actions are combined
  673. with the new actions.  Otherwise, the defaults are overridden.
  674.  
  675. m) _CMCHAR
  676.  
  677. _CMCHAR simply parses one character.  It is essentially the CCMD
  678. version of getc().
  679.  
  680. XXX default break tables for each function
  681.  
  682. 5) CCMD EXTERNAL FUNCTIONS AND MACROS:
  683.  
  684. Along with the actual parse() routine (see below), CCMD provides
  685. various supplementary functions (some of which are actually macros).
  686.  
  687. XXX Shall we use ANSI C prototyping format?  Or man page prototyping
  688. XXX format?  (Maybe our man pages should start using ANSI
  689. XXX prototyping!) 
  690.  
  691. a) cmini()
  692.  
  693. cmini() initializes CCMD by running cmbufs() and cmseti() (see below).
  694. It provides the buffers for cmbufs, and returns the address of the
  695. atom buffer.  For cmseti(), it supplies standard input, output and
  696. error.
  697.  
  698. b) cmbufs(cmdbuf, cmdlen, atombuf, atomlen, workbuf, worklen)
  699.     int *cmdbuf;
  700.     char *atombuf, *workbuf;
  701.     int cmdlen, atomlen, worklen;
  702.  
  703. This is used to initialize various buffers in the csb.  (The command
  704. buffer is an array of integers in order to hold flags about the
  705. characters in the command.)  These buffers will generally have lengths
  706. of about 200.
  707.  
  708. c) cmseti(input, output, error)
  709.     FILE *input, *output, *error;
  710.  
  711. This sets up the _cmij, _cmoj, and _cmer fields of the csb to direct
  712. or redirect input, output, and error.  Then cmtset() is called (see
  713. below).  This should be done at startup time, and whenever parsing is
  714. to be done to/from an alternate file.  (Note that cmtake(), below,
  715. takes care of this.)
  716.  
  717. d) cmtset()
  718.  
  719. This determines whether the output file is a tty, and if so it reads
  720. termcap to find out about this particular tty.  This is when changes
  721. to the terminal's attributes (notably echo, or cbreak mode) are done.
  722.  
  723. e) cmseter() and cmsetrp()
  724.  
  725. cmseter() and cmsetrp() are actually macros, but this should not
  726. affect your program.  Neither of them takes any arguments -- they
  727. simply use setjmp() to set a location.
  728.  
  729. cmseter() sets the location to return to on parsing errors, to try to
  730. parse something valid.  So, if an invalid command is typed, CCMD will
  731. try to parse again.
  732.  
  733. cmsetrp() sets where parsing will resume if the user deletes through a
  734. field that has already been parsed.  Rather than trying to unravel
  735. just the lines of code and functions executed since that field was
  736. parsed, CCMD will go back to the beginning and parse the line over.
  737.  
  738. Since cmseter() and cmsetrp() are implemented with setjmp() and
  739. longjmp(), they can be a source of memory leaks.  Therefore, you
  740. should be very aware of storage that is dynamically allocated during a
  741. parse.  Until the command is confirmed, your program may longjmp()
  742. back to the cmseter() or cmsetrp() location whenever the parse()
  743. function (see below) is in progress.
  744.  
  745. A good way to keep track of dynamic storage in this situation is to
  746. use a static pointer which gets set to NULL when it is not pointing to
  747. anything.  Then, if you enter the function and the pointer is
  748. non-NULL, you will know you have to free the storage.
  749.  
  750. f) prompt(str)
  751.     char *str;
  752.  
  753. This sets up the string that will be used for prompting.  It is
  754. generally done before the first parse of a command, inside a command
  755. parsing loop.
  756.  
  757. prompt() also resets a few internal variables, and thus should be used
  758. even when handling arguments from the command line (see cmargs()
  759. below), though a NULL prompt string is recommended in that situation.
  760. In addition, if cmseti() has not been done it will be automatically
  761. called. 
  762.  
  763. g) fdbchn (fdb1, [ fdbn, ] ... NULL)
  764.     fdb fdb1, fdbn;
  765.  
  766. When chaining multiple fdbs together, or even when using a single fdb
  767. that previously was chained, the fdbchn() routine is used.  It accepts
  768. a variable number of arguments, all fdb pointers, the last of which
  769. should be NULL.  These fdbs are linked together (using their _cmlst
  770. fields) in the order given.
  771.  
  772. Note that if an fdb is chained with other fdbs, and then later gets
  773. used on its own, you should make sure that its _cmlst field actually
  774. is NULL.  To do this, you can simply call fdbchn() with this fdb and
  775. NULL. 
  776.  
  777. h) cmargs (argc, argv);
  778.     int argc; char **argv;
  779.  
  780. This routine allows command line parsing.  It returns TRUE if there
  781. are arguments in the command line, and places them in a buffer as
  782. though they were coming in from CCMD's input stream.  They may then be
  783. parsed as desired.  On subsequent calls, and when there are no
  784. arguments present, cmargs() will return FALSE.
  785.  
  786. i) noise(str)
  787.     char *str;
  788.  
  789. This is just shorthand for parsing _CMNOI.  Note that it will affect
  790. CCMD's parsing buffers (see cmbufs, above).
  791.  
  792. j) confirm()
  793.  
  794. Similarly, shorthand for parsing _CMCFM.
  795.  
  796. k) cmtake(fnc)
  797.     int (*fnc) ();
  798.  
  799. This routine processes the standard "take" command.  It parses for a
  800. command file, as well as output and error files, and redirects CCMD's
  801. file descriptors accordingly (through cmseti(), as described above).
  802. Then it calls the given function to start parsing from the new input.
  803. It expects that on end of file the function will return.
  804.  
  805. If a take command with no filename arguments is given while within a
  806. take file, end of file is simulated.
  807.  
  808. Take files allow users to easily execute a set of "canned" commands.
  809. Command history is turned off while parsing from the alternate file,
  810. since it could be a lengthy set of commands.
  811.  
  812. l) cmpasswd (prompt)
  813.     char *prompt;
  814.  
  815. This parses a password, prompting with the specified string, in an
  816. appropriate manner.  Echo is turned off so no one can see the
  817. password, and command history is temporarily suspended so no one can
  818. look it up later.  The parsed password string is returned.
  819.  
  820. m) cmsystem(cmd)
  821.     char *cmd;
  822.  
  823. This works just like the regular system() call, except CCMD's control
  824. of the terminal is turned off while system() is running, using
  825. cmtset() (above) and cmtend() (below).
  826.  
  827. n) cmdone() or cmtend()
  828.  
  829. This function (with two names) is sort of the opposite of cmtset()
  830. above, and should be done when you are finished using CCMD, usually
  831. right before exiting or suspending the program.  It puts all the
  832. terminal attributes back the way they were before the program started.
  833.  
  834. If you catch SIGTSTP or SIGINT you should execute cmdone() in their
  835. handlers.  If you do not catch these, CCMD will catch them for you and
  836. take care of things.  Having done cmdone() yourself before suspending
  837. execution, you will want to do cmtset() (see above) as soon as the
  838. program starts up again, inside the SIGTSTP handler.
  839.  
  840. o) cmcls()
  841.  
  842. This function simply uses CCMD's knowledge of the terminal type to
  843. clear the screen.
  844.  
  845. XXX diff between datime_to_time and MM's datimetogmt -- why?
  846. XXX datime_to_time, cmxprintf, cm_set_ind (cmmisc.c), cmhist(), ...
  847.  
  848. 6) ERROR CODES:
  849.  
  850. XXX error codes returned from cmseter()
  851.  
  852. 7) PARSING:
  853.  
  854. XXX expand.  code sample
  855.  
  856. Here's the part you really want -- finally using CCMD to parse a
  857. command from the user.  Before parsing, you must either run cmini() or
  858. use the other CCMD routines, as described above, for initialization.
  859. fdbs for the desired parse should be set up.  You will need a pval
  860. structure, say "pv", and a pointer to an empty fdb structure, call it
  861. "used".
  862.  
  863. First, you tell CCMD where to go if the user types the wrong thing, by
  864. using cmseter() (see above).  Since this sets the location to go after
  865. errors, you will probably want to do 
  866.  
  867.     cmcsb._cmerr = CMxOK
  868.  
  869. to clear whatever error occurred (or you might check the error).
  870.  
  871. Next, you prompt() them for a command.  Then you'll want to set the
  872. reparse location with cmsetrp().  Thus, if the user types an incorrect
  873. command, CCMD will reprompt them and try again.  If they delete part
  874. of the command, it will reparse the command.
  875.  
  876. At this point, you pick your fdb and parse().
  877.  
  878. parse (fdbs, &pv, &used)
  879.     fdb *fdbs; pval pv; fdb *used;
  880.  
  881. "fdbs" is either the fdb you wish to use or the first of a chain of
  882. fdbs.  After the parse, "used" will contain a pointer to the fdb that
  883. was used.  This is for when you have a chain of fdbs, so you can find
  884. out just which fdb the parse succeeded on.  Knowing which fdb was used
  885. will tell you how to interpret "pv".
  886.  
  887. There you go.  You've parsed.  Don't forget to cmdone() when you're
  888. done, so the user gets their terminal back intact.
  889.  
  890. 8) COPYRIGHT:
  891.  
  892. CCMD is copyright (c) 1986, 1990 by The Trustees of Columbia University in
  893. the City of New York.  Permission is granted to any individual or
  894. institution to use, copy, or redistribute this software so long as it
  895. is not sold for profit, provided this copyright notice is retained.
  896.